package com.cskaoyan.controller.front.auth;


import com.aliyuncs.exceptions.ClientException;
import com.cskaoyan.bean.bo.front.login.LoginBo;
import com.cskaoyan.bean.vo.back.BaseRespVo;
import com.cskaoyan.bean.vo.front.login.LoginData;
import com.cskaoyan.bean.vo.front.register.RegisterBo;
import com.cskaoyan.bean.vo.front.register.RegisterMobileBo;
import com.cskaoyan.config.realm.MarketToken;
import com.cskaoyan.service.front.auth.UserLoginService;
import com.cskaoyan.util.ValidateCodeUtil;
import com.cskaoyan.util.ValidationUtils;
import com.cskaoyan.util.Md5Util;
import lombok.SneakyThrows;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;


import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

@RestController
@RequestMapping("wx/auth")
public class LoginController {
    @Autowired
    UserLoginService userLoginService;

    /**
     * 用户登录，进行shiro验证，将用户名存入session
     *
     * @param loginBo 用户名、密码对象
     * @return 用户登录信息
     */
    @PostMapping("login")
    @SneakyThrows
    public BaseRespVo login(@RequestBody @Valid LoginBo loginBo)  {

//        获取用户名密码
        String username = loginBo.getUsername();
        String password = loginBo.getPassword();

        // 获取认证
//        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);

        MarketToken authenticationToken = new MarketToken(username, password, "WX");


        // 获取主体
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(authenticationToken);
        } catch (UnknownAccountException e) {
            return BaseRespVo.invalidData("用户名或密码出现错误！");
        } catch (IncorrectCredentialsException e) {
            return BaseRespVo.invalidData("用户名或密码出现错误！");
        }
        Session session = subject.getSession();
        Serializable token = session.getId();
//        session.setTimeout(300000);

        // 通过session存入用户名
        subject.getSession().setAttribute("username", username);

        // 登录
        LoginData loginData = userLoginService.login(loginBo);
        loginData.setToken((String) token);


        return BaseRespVo.ok(loginData);
    }

    /**
     * 用户登出，销毁session
     *
     * @return 登出成功
     */
    @PostMapping("logout")
    public BaseRespVo logout() {
        SecurityUtils.getSubject().logout();
        return BaseRespVo.ok();
    }


    // TODO: 2022/10/13  //    autu/ 下面还有注册发送短信等选做

    /**
     * solution:
     */
    @PostMapping("regCaptcha")
    public BaseRespVo regCaptcha(@RequestBody RegisterMobileBo regMobileBo, HttpServletRequest request) throws ClientException {
        // 获得手机号码
        String mobile = regMobileBo.getMobile();
//        // 设置code编号 通过时间来赋值
//        SimpleDateFormat format = new SimpleDateFormat("mmssSSS");
//        String codeTime = format.format(new Date());
//        String code = codeTime.substring(1);

//通过工具类生成验证码
        String code = String.valueOf(ValidateCodeUtil.generateValidateCode(6));
        // 发送验证码
        userLoginService.sendMessage(mobile, code, request);
        return BaseRespVo.ok();
    }


    /**
     * 注册账号的逻辑
     *
     * @return BaseRespVo
     */
    @PostMapping("register")
    public BaseRespVo register(@RequestBody RegisterBo registerBo, HttpServletRequest request) {

        int code = userLoginService.authRegister(registerBo, request);

        if (code == 701) {
            return BaseRespVo.fail(705, "用户名重复");
        }
        if (code == 702) {
            return BaseRespVo.fail(705, "该号码已注册过了");
        }
        if (code == 703) {
            return BaseRespVo.fail(705, "验证码错误");
        }

        LoginBo loginBo = new LoginBo();
        loginBo.setUsername(registerBo.getUsername());
        loginBo.setPassword(registerBo.getPassword());
        LoginData loginData = userLoginService.login(loginBo);

        return BaseRespVo.ok(loginData);
    }

    /**
     * 忘记密码
     *
     * @param params  请求参数
     * @param request 获取context
     * @return BaseRespVo
     */
    @PostMapping("reset")
    public BaseRespVo reset(@RequestBody RegisterBo params, HttpServletRequest request) {
        // 获得context域
        ServletContext servletContext = request.getServletContext();
        HashMap<String, Long> reg = (HashMap<String, Long>) servletContext.getAttribute("reg");
        if (reg == null) {
            // 如果context域中没有reg
            reg = new HashMap<>();
            servletContext.setAttribute("reg", reg);
            return BaseRespVo.fail(705, "验证码错误");
        }
        Long addTime = reg.remove(params.getCode());
        if (addTime == null) {
            // 验证码错误
            return BaseRespVo.fail(705, "验证码错误");
        }
        // 验证码正确 查看有没有超时
        // 将超时时间转换为Long
        long tempTime = 5 * 60 * 1000;
        // 现在的时间
        long nowTime = System.currentTimeMillis();
        // 判断添加的时间＋超时时间有没有大于现在的时间
        if ((addTime + tempTime) < nowTime) {
            // 验证码超时了
            return BaseRespVo.fail(705, "验证码错误");
        }

        int code = userLoginService.resetPasswordByMobile(params);
        if (code == 1) {
            return BaseRespVo.ok("密码重置成功");
        } else {
            return BaseRespVo.fail(705, "用户不存在");
        }

    }


}
